#include "FileDownloader.h"

#include "Log.h"
#include "SafeDataFile.h"
#include "ErrorCode.h"

FileDownloader::FileDownloader() {
    getWorkThread().setAutoDelete(true);
}

FileDownloader::~FileDownloader() {
    LOG_DEDUG("FileDownloader:%p, destroyed", this);
}


bool FileDownloader::doWork() {
    bool result = true;
    try {
        //连接服务器
        result = mhttpCommunictor.connect(muriInfo);
        if (result) {
            retryCount = MAX_RETRY_COUNT;
            //发送http报文
            char range[100];
            snprintf(range, sizeof (range), "bytes=%d-", mdownloaded);
            Utility::StringMap requstProperties{{RANGE, range}, {IF_RANGE, header.properties[ETAG]}};
            ssize_t	ret = mhttpCommunictor.sendHeader(requstProperties);
            //解析http报头
            mhttpCommunictor.parseHeader(header);

            if (200 != header.statusCode && 206 != header.statusCode) {
                result = false;
                LOG_DEDUG("warning:not found file [%s]\n",header.fileName.data());
            } else {
                if (200 == header.statusCode) {
                    mdownloaded = 0;
                    header.fileSize = header.contentLength;
                } else {
                    std::string& value = header.properties[CONTENT_RANGE];
                    std::string::size_type index = value.find_last_of('/');
                    if (std::string::npos == index) {
                        BUILD_EXCEPTION_PRINTF(FirmwareError::HTTP_HEADER_ERROR, "%s:%s error,not found total size!", CONTENT_RANGE.data(), value.data());
                    }
                    header.fileSize = std::strtol(value.data() + index + 1, nullptr, 10);
                }

                mdownloaded += download(header);
                if (header.fileSize == mdownloaded) {
                    result = true;
                    mfinishCallback(*this, header.fileName);
                } else {
                    result = false;
                    LOG_ERROR("data not download completed, reconnecting...");
                }
            }
        } else {
            LOG_ERROR("downloader connect failed, reconnecting...");
        }
    } catch(std::exception& ex) {
        result = false;
        LOG_ERROR(ex.what());
    }

    mhttpCommunictor.msocket.close();

    if (result || 0 >= --retryCount) {
        getWorkThread().stop(false);
    } else {
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }

    return result;
}

ssize_t FileDownloader::download(HttpHeader header) {
    int oflags = O_CREAT | O_WRONLY | O_CLOEXEC;
    if (0 == mdownloaded) {
        oflags |= O_TRUNC;
    } else {
        oflags |= O_APPEND;
    }
    SafeDataFile file{header.fileName, oflags, 0755};

    ssize_t len;
    ssize_t sum = 0;
    NetworkString buffer(MAX_BUFFER_SIZE << 2, 0);
    while((len = mhttpCommunictor.msocket.recv(buffer, 0)) > 0) {
        file.write(buffer.data(), len);
        sum += len;
        printProgress(header.fileName.data(), mdownloaded + sum, header.fileSize);
        if (header.contentLength == sum) {
            break;
        }
    }
    if (header.contentLength != sum) {
        std::string errorMassage{"download error:"};
        buildErrorMessage(len, errno, errorMassage);
        LOG_ERROR(errorMassage.data());
    }
    file.syncToPersistence();
    file.close();
    return sum;
}


//打印进度条
void FileDownloader::printProgress(const char *fileName, ssize_t sum, ssize_t fileSize) {
    float percent = ((float)sum / fileSize) * 100;
    printf("%s %7.2f%% %.2f/%.2f MB\r", fileName, percent, sum / (1024.0 * 1024.0),fileSize / (1024.0 * 1024.0));
    fflush(stdout);
}

